<template>
  <el-card class="pdf-merge-box">
    <template #header>
      <h2 class="flex items-center">
        <el-icon class="mr-2"><Document /></el-icon>
        PDF合并工具
      </h2>
    </template>

    <!-- 文件上传区域 -->
    <el-upload
      multiple
      :limit="MAX_PDF_FILE"
      :auto-upload="false"
      :on-change="handleFileChange"
      :show-file-list="false"
    >
      <template #trigger>
        <el-button type="primary" :icon="Upload">
          {{ `选择PDF文件（最多${MAX_PDF_FILE}个）` }}
        </el-button>
      </template>
      <!-- <template #tip>
        <div class="el-upload__tip">支持拖放文件到此处上传</div>
      </template> -->
    </el-upload>
    <!-- 进度条 -->
    <el-progress
      v-if="
        mergeNum === MergeStatus.InProgress || mergeNum === MergeStatus.Success
      "
      :percentage="percentage"
      :striped="true"
      :striped-flow="true"
      class="progress"
    />
    <!-- 拖拽排序区域 -->
    <div v-if="fileList.length" class="drag-container">
      <draggable
        v-model="fileList"
        item-key="uid"
        @start="onDragStart"
        @end="onDragEnd"
      >
        <template #item="{ element, index }">
          <div class="file-item drag-handle">
            <div class="file-info">
              <span class="file-name">{{ element.name }}</span>
              <div class="file-meta">
                <el-tag size="small">{{ formatSize(element.size) }}</el-tag>
                <el-tag type="info" size="small">
                  {{ getFileExtension(element.name) || "pdf" }}
                </el-tag>
              </div>
            </div>
            <el-icon class="delete-btn" @click="removeFile(index)">
              <Delete />
            </el-icon>
          </div>
        </template>
      </draggable>
      <div class="drag-tip">
        <el-icon><Sort /></el-icon>
        拖拽修改合并文件顺序
      </div>
    </div>
    <div v-else class="drag-container-box">
      <div> 请选择要合并的文件 </div>
    </div>

    <!-- 操作按钮区域 -->

    <div class="action-area">
      <el-button
        :type="statusTypeMap[mergeNum]"
        :loading="mergeNum === MergeStatus.InProgress"
        :disabled="
          mergeNum === MergeStatus.InProgress ||
          mergeNum === MergeStatus.Success ||
          mergeNum === MergeStatus.Failed
        "
        @click="handleMerge"
      >
        {{ statusLabels[mergeNum] }}
      </el-button>
      <template v-if="mergeNum === MergeStatus.Success">
        <el-button type="info" plain @click="previewVisible = true">
          <template #icon><View /></template>
          在线预览
        </el-button>
        <el-button type="primary" plain @click="handleDownload">
          <template #icon><Download /></template>
          下载文档
        </el-button>
      </template>
    </div>

    <!-- 预览对话框 -->
    <el-dialog v-model="previewVisible" title="PDF预览" width="85%">
      <VuePdfEmbed
        v-if="previewVisible"
        annotation-layer
        text-layer
        :source="previewUrl"
      />

      <template #footer>
        <el-button @click="previewVisible = false">关闭</el-button>
        <el-button type="primary" @click="handleDownload">立即下载</el-button>
      </template>
    </el-dialog>
  </el-card>
</template>

<script setup lang="ts">
import { ref, onBeforeUnmount, onMounted } from "vue";
import { PDFDocument } from "pdf-lib";
import draggable from "vuedraggable";
import VuePdfEmbed from "vue-pdf-embed";

import { useFakeProgress } from "./useFakeProgress";
import {
  MAX_PDF_FILE,
  MergeStatus,
  statusLabels,
  statusTypeMap,
} from "../types/Merge";

import {
  ElMessage,
  ElIcon,
  ElCard,
  ElUpload,
  ElButton,
  ElDialog,
  UploadFile,
} from "element-plus";
import {
  Document,
  Upload,
  Delete,
  Download,
  View,
  Sort,
} from "@element-plus/icons-vue";

import "vue-pdf-embed/dist/styles/annotationLayer.css";
import "vue-pdf-embed/dist/styles/textLayer.css";

// 响应式状态
const fileList = ref<UploadFile[]>([]);
const mergeNum = ref<MergeStatus>(0);
const mergedBlob = ref<Blob | null>(null);
const previewVisible = ref(false);
const previewUrl = ref("");
const fakeProgress = useFakeProgress();
const percentage = fakeProgress.percentage;
const { start, end } = fakeProgress;

onMounted(() => {
  mergeNum.value = MergeStatus.Started;
});
// 处理文件选择
const handleFileChange = (uploadFile: UploadFile): void => {
  if (fileList.value.length >= MAX_PDF_FILE) {
    ElMessage.warning(`最多选择${MAX_PDF_FILE}个文件`);
    return;
  }
  const newFile: UploadFile = {
    uid: uploadFile.uid,
    name: uploadFile.name,
    size: uploadFile.size,
    raw: uploadFile.raw,
    status: "success",
  };
  console.log(JSON.stringify(fileList.value));
  fileList.value = [...fileList.value, newFile];
};

// 合并PDF
const handleMerge = async () => {
  if (fileList.value.length < 2) {
    ElMessage.warning("单个文件无法合并，请继续添加文件");
    return;
  }
  start();
  mergeNum.value = MergeStatus.InProgress;
  try {
    const mergedPdf = await PDFDocument.create();
    for (const file of fileList.value) {
      const arrayBuffer = await (file.raw as any).arrayBuffer();
      const pdfDoc = await PDFDocument.load(arrayBuffer);
      const pages = await mergedPdf.copyPages(pdfDoc, pdfDoc.getPageIndices());
      pages.forEach((p) => mergedPdf.addPage(p));
    }

    const mergedBytes = await mergedPdf.save();
    mergedBlob.value = new Blob([mergedBytes], { type: "application/pdf" });
    // 创建预览iframe地址
    previewUrl.value = URL.createObjectURL(mergedBlob.value);
    mergeNum.value = MergeStatus.Success;
    ElMessage.success("合并成功！");
  } catch (error) {
    mergeNum.value = MergeStatus.Failed;
    ElMessage.error("合并失败");
  } finally {
    end();
  }
};

// 删除文件
const removeFile = (index: number) => {
  fileList.value.splice(index, 1);
  ElMessage.success("已移除文件");
};

// 格式化文件大小
const formatSize = (bytes: number) => {
  const units = ["B", "KB", "MB", "GB"];
  let size = bytes;
  let unit = 0;
  while (size >= 1024 && unit < units.length - 1) {
    size /= 1024;
    unit++;
  }
  return `${size.toFixed(2)} ${units[unit]}`;
};
const getFileExtension = (filename: string) => {
  if (typeof filename !== "string") return "";
  const dotIndex = filename.lastIndexOf(".");
  if (dotIndex <= 0 || dotIndex === filename.length - 1) return "";
  return filename.slice(dotIndex + 1);
};

// 下载处理
const handleDownload = () => {
  if (!mergedBlob.value) return;
  const filename = `合并文档-${new Date().toISOString().slice(0, 10)}.pdf`;
  const link = document.createElement("a");
  link.href = URL.createObjectURL(mergedBlob.value);
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  setTimeout(() => {
    document.body.removeChild(link);
    URL.revokeObjectURL(link.href);
  }, 100);
};

// 交互逻辑增强
const onDragStart = () => {
  document.body.style.cursor = "grabbing";
  ElMessage({
    type: "info",
    message: "开始拖拽调整顺序",
    duration: 1500,
    customClass: "drag-message",
  });
};

const onDragEnd = () => {
  document.body.style.cursor = "";
  mergedBlob.value ? (mergeNum.value = MergeStatus.Retrying) : null;
  ElMessage({
    type: "success",
    message: "拖拽调整完成",
    duration: 1500,
    customClass: "drag-message",
  });
};
// 清理资源
onBeforeUnmount(() => {
  if (previewUrl.value) {
    URL.revokeObjectURL(previewUrl.value);
  }
});
</script>

<style lang="scss" scoped>
// 定义主题变量
$primary-color: var(--el-color-primary);
$danger-color: var(--el-color-danger);
$border-color: var(--el-border-color);
$text-secondary: var(--el-text-color-secondary);

:deep(.el-progress__text) {
  min-width: initial !important;
}

.pdf-merge-box {
  width: 90%;
  max-width: 800px;
  margin: 20px auto;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
  border-radius: 8px;
  min-height: 40px;

  .drag-container {
    border: 2px dashed $primary-color;
    border-radius: 6px;
    padding: 15px;
    background: #f8f9fe;
    margin-top: 1rem;
    counter-reset: file-counter; // css序号初始化

    .drag-tip {
      color: $primary-color;
      font-size: 0.675rem;
      display: flex;
      align-items: center;
      justify-content: flex-end;
      gap: 0.5rem;
    }
  }
  .drag-container-box {
    border: 2px dashed $primary-color;
    border-radius: 6px;
    padding: 12px 20px 30px 20px;
    box-sizing: border-box;
    background: #f8f9fe;
    margin-top: 1rem;
    // height: 30px;
    font-size: 12px;
    color: #909399;
    text-align: start;
    // line-height: 20px;
  }
  .progress {
    margin-top: 16px;
  }

  .file-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: relative;
    counter-reset: section;
    padding: 0.75rem;
    margin: 0.5rem 0;
    background: #fff;
    border: 1px solid $border-color;
    border-radius: 6px;
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);

    &:hover {
      transform: translateX(5px);
      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }

    &.sortable-chosen {
      cursor: grabbing;
      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
      transform: scale(1.02) rotateZ(1deg);
      z-index: 2;
      opacity: 0.9;
    }

    &::before {
      content: counter(file-counter);
      counter-increment: file-counter;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 24px;
      height: 24px;
      background: $primary-color;
      color: white;
      border-radius: 50%;
      margin-right: 0.75rem;
      font-size: 0.875rem;
      transition: all 0.3s ease;
    }

    .file-info {
      flex: 1;
      min-width: 0;
      display: inline-block;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;

      .file-name {
        font-size: 0.875rem;
        font-weight: 500;
      }

      .file-meta {
        margin-top: 0.25rem;
        display: flex;
        gap: 0.5rem;

        .el-tag {
          font-size: 0.75rem;
          line-height: 1.2;
        }
      }
    }

    .delete-btn {
      color: $danger-color !important;
      cursor: pointer;
      padding: 0.5rem;
      transition: all 0.2s ease;

      &:hover {
        transform: scale(1.1);
        color: hsl(0, 89%, 65%) !important;
      }
    }
  }

  .action-area {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 1.5rem;
    .el-button {
      padding: 8px 15px;
    }
  }

  .preview-iframe {
    width: 100%;
    height: 70vh;
    border: none;
    border-radius: 4px;
  }
}

// 动画定义
@keyframes bounce {
  0%,
  100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-2px);
  }
}

// 响应式处理
@media (max-width: 768px) {
  .pdf-merge-box {
    width: 98%;
    margin: 10px auto;

    .file-item {
      padding: 0.5rem;

      &::before {
        width: 20px;
        height: 20px;
        font-size: 0.75rem;
      }
    }

    .preview-iframe {
      height: calc(100vh - 150px);
    }

    .el-dialog {
      width: 90% !important;
      height: 90vh !important;
    }
  }
}
</style>
